Skip to content

ci: sync fork and wait for remake in OSC dev - #24

Merged
birme merged 3 commits into
mainfrom
ci/sync-fork-dev
Sep 30, 2026
Merged

birme merged 3 commits into
mainfrom
ci/sync-fork-dev

Conversation

@birme

@birme birme commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a GitHub Action that, on every push to main (and manually via workflow_dispatch), triggers a sync-fork of this upstream repo in OSC dev and waits until the resulting remake finishes.

Flow (osaas-maker-manager on maker.svc.dev.osaas.io):

  1. POST /sync-fork with this repo's URL
  2. Poll GET /sync-fork/:id until succeeded (fails on failed)
  3. Poll GET /maker?repositoryUrl=... until the order phase is DONE (fails on FAILED/ERROR)

Required before this works: repo/org Actions secret OSC_DEV_MAKER_API_KEY (dev maker-manager bearer API key). The job fails fast with a clear error if it is missing.

Test plan

  • Add the secret, run the workflow via workflow_dispatch, confirm it ends green after the dev remake completes

Lessons

The sync-fork job already remakes an existing order itself (osaas-service-builder), so the workflow never calls /remaker; it only waits on the order phase. A remake replaces the order with a new id, so polling is by repositoryUrl, not order id.

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com

Co-Authored-By: Claude <noreply@anthropic.com>
@birme birme self-assigned this Sep 30, 2026
@birme

birme commented Sep 30, 2026

Copy link
Copy Markdown
Contributor Author

Research Review

Verdict: no blocks-merge findings. Endpoints, field names, auth and response shapes all match source. Two polling edge cases are worth fixing or accepting knowingly. This PR is byte-identical (added lines hash-match) across all 6 runner PRs (web-runner#62, python-runner#24, wasm-runner#25, golang-runner#21, dotnet-runner#20, php-runner#10), so the findings apply to each.

Verified

  • POST /sync-fork: body {repositoryUrl} and response {jobId} match osaas-maker-manager/src/api_sync_fork.ts and NewSyncForkJobRequest/NewSyncForkJobResponse in src/model.ts:165-175. A URL not starting with https://github.com/ gives 400. REPO_URL=https://github.com/${{ github.repository }} satisfies this.
  • GET /sync-fork/:id: returns {jobId,status,repositoryUrl,reason?,message?,conflictFiles?} (SyncForkJobStatusResponse, src/model.ts:207). status is a free string documented as pending/running/succeeded/failed. The workflow's .status, .reason and .message reads are correct. 404 on unknown id is tolerated by || echo '{}'.
  • GET /maker?repositoryUrl=: MakerQuery accepts repositoryUrl (additionalProperties:false, so no stray params are sent). The response is MakerJobResponseArray, an array of {order, original?, lastRemadeRelease?}. .[0].order.status.phase is correct. The filter is an exact spec.githubRepository === repositoryUrl match.
  • Phase enum in osaas-lib-maker/src/order/model.ts:11 is exactly NEW/PENDING/RUNNING/FAILED/ERROR/DONE. The case statement covers the terminal ones.
  • Auth: all three routes sit behind @fastify/bearer-auth with ApiKey.getApiKey(), so Authorization: Bearer <key> is right. The service-builder uses the same header (osaas-service-builder/src/index.ts:808-820).
  • Lessons claim confirmed. osaas-service-builder/src/cli.ts:119-200 (sync-fork) does checkExistingOrder (GET /maker?repositoryUrl=, first .order.orderId) then remakeOrder (POST /remaker {orderId}). osaas-maker-manager/src/utils/remaker.ts removes the old order and places a NEW order with a new id. Polling by repositoryUrl rather than order id is therefore correct.
  • Lessons section and Claude trailer are present.

Polling race analysis

  • The stale-DONE race in the normal path does not occur. Remake runs inside the sync-fork k8s job (cli.ts), before the container exits. /sync-fork/:id only reports succeeded after the new NEW order has been placed. Step 3 therefore starts after the old order is gone. The remove-then-place gap in remaker.ts is closed before step 3 begins. NEW is not terminal in the case statement, so it keeps polling.
  • Stale order after a swallowed remake failure (worth verifying). remakeOrder in osaas-maker-manager/src/utils/remaker.ts returns 400 "Can not remake active orders" if the existing order is PENDING or RUNNING. Two pushes to main in quick succession can hit this, and the workflow's concurrency group does not stop it while a previous dev build is still running. cli.ts catches the remake error and only does Log().warn. The job still exits 0 and reports succeeded. Step 3 then waits on the older in-flight order and reports green on its DONE, although the newest commit was never rebuilt. A mitigation is to record .[0].order.orderId before POST and require a changed id (or a lastRemadeRelease/creation change) before accepting DONE.
  • No existing order (worth verifying). cli.ts only remakes if checkExistingOrder finds one. If a runner repo has no dev order, the job succeeds, GET /maker returns [], and the loop prints NOT_FOUND for 120 x 20s = 40 min before failing. Consider failing fast after a few consecutive NOT_FOUND polls, with a clear message. Also confirm each of the 6 repos has a dev order whose spec.githubRepository is exactly https://github.com/Eyevinn/<repo> (case, no .git, no trailing slash). I could not query dev to check this.
  • .[0] takes the first order. name is derived from the URL, so duplicates should not exist, but ordering of getOrders() is not defined by the API.

Needs Verification (minor)

  • Trigger sync-fork step: jq -r '.jobId' yields the string null on an unexpected body. Step 2 then polls a 404 id for 20 min. curl -sf with pipefail also exits with no message on a 4xx or 5xx. Add a [ "$JOB_ID" != "null" ] guard and drop -f (or print the body).
  • Timeouts: 60 x 20s = 20 min for the sync job, 120 x 20s = 40 min for the remake, and timeout-minutes: 60. No measured dev latency (p50/max) is cited. The sync job runs ensureStableImage, which can build a docker image, and 20 min may be tight. This is a CI-side background path, not a request path, so worth verifying rather than blocking.
  • Secret OSC_DEV_MAKER_API_KEY could not be checked from here (no permission to list repo/org secrets). The PR states it must be added before first run. The fail-fast guard is good.
  • The workflow triggers on every push to main, including docs-only changes. This is a design choice, noted for awareness.

Adjacent Stubs Detected

None. The file is new; a grep for undefined : undefined, || undefined, TODO/FIXME and empty catches found nothing. The || echo '{}' / || echo "UNKNOWN" fallbacks are intentional and handled.

Orphaned Files Detected

None. A workflow file is an entry point.

Object Shape Verification

Not applicable. No object spreads; shell and jq only.

Escape Hatch Coverage

No terminal-rejection branch is added to a service. The workflow's own failure exits are reachable only on genuine failures or timeouts. The main legitimate false-fail is the 40 min NOT_FOUND path above.

Contract diff

No request handler or server timeout changed. This PR adds only .github/workflows/sync-fork-dev.yml. I read api_sync_fork.ts, api_maker.ts, utils/remaker.ts and prepare_service/provider.ts (all unmodified) as consumers.

Impact Analysis

  • Blast radius: only each runner repo's Actions and the dev maker (a dev remake per push to main). No prod, and no shared library touched.
  • Downstream consumers: none.
  • Coordinated changes needed: add the OSC_DEV_MAKER_API_KEY secret (repo or org level) before merge or first run.
  • Breaking change risk: low.

Risks Not Tested

  • Live behaviour against maker.svc.dev.osaas.io was not exercised: no workflow run, no curl with a real key.
  • The swallowed-remake-failure path (active order at the time of sync) was reasoned from remaker.ts and cli.ts, not reproduced.
  • Whether each of the 6 repos has a matching dev order (exact githubRepository string) is unverified.
  • The k8s status mapping (mapJobToPrepareJob) to pending/running/succeeded/failed was read only partially. The spec string in the model documents it.
  • Whether the sync-fork job's push to the dev fork could re-trigger this workflow: it pushes to the fork (not upstream), so it should not, but I did not trace it end to end.
  • Sync job and remake durations are not measured.

Reviewed by PR Research Validator. This review checks whether code is based on verified sources rather than assumptions.

birme and others added 2 commits September 30, 2026 09:34
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@birme
birme merged commit 2132f1f into main Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant